/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.netbeans.editor; import java.lang.ref.WeakReference; import java.util.ArrayList; import javax.swing.text.Document; import javax.swing.text.JTextComponent; import javax.swing.text.BadLocationException; /** * The last several jumps in either the current file * or across several files is stored here in the list. * It's possible to track this list. * * @author Miloslav Metelka * @version 1.00 */ public class JumpList { /** Maximum size to which the list will be shrinked * if it exceeds the THRESHOLD_SIZE. */ private static final int MAX_SIZE = 50; /** Reaching this count means that the size should be checked * and possibly shrinked to the MAX_SIZE. */ private static final int CHECK_COUNT = 10; /** Current jump list entry */ private static Entry currentEntry; private static int checkCnt; public static void checkAddEntry() { JTextComponent c = Utilities.getLastActiveComponent(); if (c != null) { checkAddEntry(c, c.getCaret().getDot()); } } public static void checkAddEntry(JTextComponent c) { checkAddEntry(c, c.getCaret().getDot()); } public static void checkAddEntry(JTextComponent c, int pos) { if (currentEntry == null || currentEntry.getComponent() != c || currentEntry.getPosition() != pos ) { addEntry(c, pos); } } public static void addEntry(JTextComponent c, int pos) { try { Entry e = new Entry(c, pos, currentEntry); currentEntry = e; if (++checkCnt >= CHECK_COUNT) { // perform size check sizeCheck(); } } catch (BadLocationException e) { // entry not added } } /** * @param c current component. It's used to compare the current * component and position with those stored in the entries. */ public static void jumpPrev(JTextComponent c) { int dotPos = c.getCaret().getDot(); if (currentEntry != null) { while (true) { int entryPos = currentEntry.getPosition(); JTextComponent entryComp = currentEntry.getComponent(); if (entryComp != null && (entryComp != c || (entryPos >= 0 && entryPos != dotPos))) { if (currentEntry.setDot()) { break; } } if (currentEntry.prev != null) { // must check not to end up with null currentEntry = currentEntry.prev; } else { break; // break when on the last entry } } } } /** * @param c current component. It's used to compare the current * component and position with those stored in the entries. */ public static void jumpNext(JTextComponent c) { int dotPos = c.getCaret().getDot(); if (currentEntry != null) { while (true) { int entryPos = currentEntry.getPosition(); JTextComponent entryComp = currentEntry.getComponent(); if (entryComp != null && (entryComp != c || (entryPos >= 0 && entryPos != dotPos))) { if (currentEntry.setDot()) { break; } } if (currentEntry.next != null) { // must check not to end up with null currentEntry = currentEntry.next; } else { break; // break when on the last entry } } } } /** * @param c current component. It's used to compare the current * component to those stored in the jump list entries. */ public static void jumpPrevComponent(JTextComponent c) { if (currentEntry != null) { while (true) { JTextComponent entryComp = currentEntry.getComponent(); if (entryComp != null && entryComp != c) { if (currentEntry.setDot()) { break; } } if (currentEntry.prev != null) { // must check not to end up with null currentEntry = currentEntry.prev; } else { break; // break when on the last entry } } } } /** * @param c current component. It's used to compare the current * component to those stored in the jump list entries. */ public static void jumpNextComponent(JTextComponent c) { if (currentEntry != null) { while (true) { JTextComponent entryComp = currentEntry.getComponent(); if (entryComp != null && entryComp != c) { if (currentEntry.setDot()) { break; } } if (currentEntry.next != null) { // must check not to end up with null currentEntry = currentEntry.next; } else { break; // break when on the last entry } } } } public static String dump() { StringBuffer sb = new StringBuffer(); int i = 0; Entry e = currentEntry; if (e != null) { while (true) { if (e.prev != null) { e = e.prev; i--; } else { break; } } while (e != null) { JTextComponent comp = e.getComponent(); String docStr = (comp != null) ? (String)comp.getDocument().getProperty(Document.TitleProperty) : "<Invalid document>"; // NOI18N if (docStr == null) { // no title property docStr = "Untitled"; // NOI18N } sb.append("[" + i++ + "]=" + docStr + ", " + e.getPosition() + "\n"); // NOI18N e = e.next; } } else { // null current entry sb.append("Empty list"); // NOI18N } return sb.toString(); } private static void sizeCheck() { int cnt = MAX_SIZE; Entry e = currentEntry; while (e != null && cnt > 0) { e = e.prev; } if (e != null) { // reached the one that should be the first e.makeFirst(); } } public static class Entry { /** ID of the stored position component */ private int componentID; /** ID of the position stored in the document */ private int posID; /** Previous entry in the linked list */ Entry prev; /** Next entry in the linked list */ Entry next; Entry(JTextComponent component, int offset, Entry last) throws BadLocationException { componentID = Registry.getID(component); posID = ((BaseDocument)component.getDocument()).storePosition(offset); if (last != null) { // apend after the last entry last.next = this; this.prev = last; } } public int getPosition() { JTextComponent c = Registry.getComponent(componentID); int pos = -1; if (c != null) { pos = ((BaseDocument)c.getDocument()).getStoredPosition(posID); } return pos; } public JTextComponent getComponent() { return Registry.getComponent(componentID); } /** Set the dot to the component and position * stored in the mark. * @return true if the caret was successfully moved */ public boolean setDot() { JTextComponent c = getComponent(); if (c != null) { if (Utilities.getLastActiveComponent() != c) { Utilities.requestFocus(c); // possibly request for the component } int pos = getPosition(); if (pos >= 0 && pos <= c.getDocument().getLength()) { c.getCaret().setDot(pos); // set the dot return true; } } return false; } void makeLast() { if (next != null) { next.prev = null; next = null; } } void makeFirst() { if (prev != null) { prev.next = null; prev = null; } } protected void finalize() throws Throwable { JTextComponent c = Registry.getComponent(componentID); if (c != null) { ((BaseDocument)c.getDocument()).removeStoredPosition(posID); } super.finalize(); } } } /* * Log * 6 Gandalf-post-FCS1.4.1.0 3/8/00 Miloslav Metelka * 5 Gandalf 1.4 1/13/00 Miloslav Metelka * 4 Gandalf 1.3 1/10/00 Miloslav Metelka * 3 Gandalf 1.2 11/14/99 Miloslav Metelka * 2 Gandalf 1.1 11/9/99 Miloslav Metelka * 1 Gandalf 1.0 11/8/99 Miloslav Metelka * $ */